package comunicacion.vision;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

import java.util.ArrayList;

import javax.vecmath.Point3d;

/**
 * @author IAR
 */
public class DoraemonServer extends Thread {
	
	private static DoraemonServer instance = null;
	
	// string con todo el paquete de Doraemon
	private String received;
	
	// atributos utilizados para intercambiar mensajes UDP con el servidor
	private DatagramSocket socketIn;
	
	// coordenadas y rotaci�n del objeto controlado por mi
	private double coordX;
	private double coordY;
	private double rot;
	
	// coordenadas y rotacion de los objetos
	private double [] coorXObj = new double[DoraemonConfig.OBJECTS];
	private double [] coorYObj = new double[DoraemonConfig.OBJECTS];
	private double [] rotObj = new double[DoraemonConfig.OBJECTS];
	
	private DoraemonServer() {
		try {
			socketIn = new DatagramSocket(DoraemonConfig.PORT_CLIENTE);
		} catch (SocketException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * @return Retorna la �nica instancia de la clase.
	 */
	public static DoraemonServer getInstance() {
		if (instance == null) {
			instance = new DoraemonServer();
		}
		return instance;
	}
	
	/**
	 * @return La abcisa del robot propio expresada en mil�metros.
	 */
	public double getX() {
		return coordX;
	}
	
	/**
	 * @return La ordenada del robot propio expresada en mil�metros.
	 */
	public double getY() {
		return coordY;
	}
	
	/**
	 * @return La rotaci�n del robot propio expresada en grados.
	 */
	public double getRot() {
		return rot;
	}

	/**
	 * @param obj Indice del objeto seg�n el ordenamiento de que realiza el sistema Doraemon.
	 * @return La abcisa del objeto obj expresada en mil�metros.
	 */
	public double getXObject(int obj) {
		return coorXObj[obj];
	}
	
	/**
	 * @param obj Indice del objeto seg�n el ordenamiento de que realiza el sistema Doraemon.
	 * @return La ordenada del objeto obj expresada en mil�metros.
	 */
	public double getYObject(int obj) {
		return coorYObj[obj];
	}
	
	/**
	 * @param obj Indice del objeto seg�n el ordenamiento de que realiza el sistema Doraemon.
	 * @return La rotaci�n del objeto obj expresada en grados.
	 */
	public double getRotObject(int obj) {
		return rotObj[obj];
	}
	
	/**
	 * @return Una tupla (x, y, r) que representa la posici�n del robot propio.
	 */
	public Point3d getPos() {
		synchronized (this) {
			return new Point3d(coordX, coordY, rot);
		}
	}
	
	/**
	 * @param obj Indice del objeto seg�n el ordenamiento de que realiza el sistema Doraemon.
	 * @return Una tupla (x, y, r) que representa la posici�n del objeto obj.
	 */
	public Point3d getPosObject(int obj) {
		synchronized (this) {
			return new Point3d(this.coorXObj[obj], this.coorYObj[obj], this.rotObj[obj]);
		}
	}
	
	/**
	 * @return Un vector de posiciones correspondiente a las tuplas (x, y, r) de cada uno de los objetos diferentes al propio.
	 */
	public Point3d [] getPosObject() {
		Point3d [] result;
		int j = 0;
		synchronized (this) {
			result = new Point3d [DoraemonConfig.OBJECTS-1];
			for (int i=0; i<DoraemonConfig.OBJECTS; i++) {
				if(i!=DoraemonConfig.OWN_NAME_SUFIX) {
					result[j] = new Point3d (this.coorXObj[i], this.coorYObj[i], this.rotObj[i]);
					j++;
				}					
			}
			return result;
		}
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Thread#run()
	 */
	public void run() {
		byte[] buffer = new byte[DoraemonConfig.LARGO_MAX_MSG];
		DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
		String[] data;
		
		int index;

		while (true) {
			try {
				socketIn.receive(packet);				
				received = new String(packet.getData(), "ascii");
				received = received.substring(0,packet.getLength());
				data = received.split("\n");
				
				// Array con capacidad para almacenar la info de todos los objetos m�viles que captura el sistema de visi�n
				ArrayList<String[]> objetos = new ArrayList<String[]>(DoraemonConfig.OBJECTS);

				for (int i=2; i<data.length; i++) {
					objetos.add(data[i].split(" "));
				}
	
				for (String[] objeto : objetos) {
					if (objeto[1].equals(DoraemonConfig.OBJ_NAME_PREFIX+DoraemonConfig.OWN_NAME_SUFIX)) {
						if (objeto[2].equals("Found")) {
							coordX = Float.parseFloat(objeto[3]);
							coordY = Float.parseFloat(objeto[4]);
							// Doraemon entrega rotaciones rotadas 45 grados respecto al 0
							rot = Float.parseFloat(objeto[6]) * 180 / Math.PI;
							if (rot < -180) {
								rot += 360;
							}
						}
					}
					else if (objeto[1].startsWith(DoraemonConfig.OBJ_NAME_PREFIX)) {
						//index = new Integer(objeto[1].substring(objeto[1].length()-1)).intValue()-1;
						index = new Integer(objeto[1].substring(objeto[1].length()-1)).intValue();
						//System.out.println("index"+index);
						if (objeto[2].equals("Found")) {
							coorXObj[index] = Float.parseFloat(objeto[3]);
							coorYObj [index] = Float.parseFloat(objeto[4]);
							// Doraemon entrega rotaciones rotadas 45 grados respecto al 0
							rotObj [index] = Float.parseFloat(objeto[6]) * 180 / Math.PI;
							if (rotObj[index] < -180) {
								rotObj[index] += 360;
							}
						}
					}
				}
			}
			catch (Exception ex) {
				ex.printStackTrace();
			} // no hay mensajes para procesar
		} // while
	}
}